package com.arpa.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.ShipmentWarehouseValidate;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.ntocc.common.domain.entity.Shipment;
import com.arpa.ntocc.common.service.IShipmentService;
import com.arpa.wms.cache.*;
import com.arpa.wms.common.util.OrderIdGeneratorUtil;
import com.arpa.wms.domain.dto.InitializationDTO;
import com.arpa.wms.domain.dto.InitializationExcelDTO;
import com.arpa.wms.domain.dto.InitializationItemDTO;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.*;
import com.arpa.wms.domain.vo.InitializationItemVO;
import com.arpa.wms.domain.vo.InitializationVO;
import com.arpa.wms.mapper.InitializationMapper;
import com.arpa.wms.mapper.LocationMapper;
import com.arpa.wms.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.arpa.wms.domain.consts.CodeConst.GROUP_CODE;
import static com.arpa.wms.domain.consts.CodeConst.SUPPLIER_CODE;
import static com.arpa.wms.domain.consts.CommonConst.*;
import static com.arpa.wms.domain.consts.NumConst.*;
import static com.arpa.wms.domain.consts.TipConst.SUPPLIER_NAME;
import static com.arpa.wms.domain.consts.TipConst.*;

/**
 * 期初 服务 实现类
 * @author jinss
 * @date 2020-09-24 14:25:22
 **/
@Service
@Log4j2
public class InitializationServiceImpl extends ServiceImpl<InitializationMapper, Initialization> implements IInitializationService {

    DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private IInitializationItemService initializationItemService;
    @Autowired
    private IShipmentService shipmentService;
    @Autowired
    private IWarehouseShipmentService warehouseShipmentService;
    @Autowired
    private IInventoryStatusService inventoryStatusService;
    @Autowired
    private IInventoryService inventoryService;
    @Autowired
    private InitializationCache initializationCache;
    @Autowired
    private WarehouseCache warehouseCache;
    @Autowired
    private WarehouseSpaceCache warehouseSpaceCache;
    @Autowired
    private LocationCache locationCache;
    @Resource
    private LocationMapper locationMapper;
    @Autowired
    private GoodsCache goodsCache;
    @Autowired
    private GoodsUnitConversionCache goodsUnitConversionCache;
    @Autowired
    private BatchRuleCache batchRuleCache;
    @Autowired
    private PartyCache partyCache;
    @Autowired
    private UnitCache unitCache;
    @Autowired
    private IInboundService inboundService;
    @Autowired
    private IInboundItemService inboundItemService;
    @Autowired
    private IInventoryRecordService inventoryRecordService;
    @Autowired
    private IWarehouseService iWarehouseService;
    @Autowired
    private IWarehouseSpaceService iWarehouseSpaceService;
    @Autowired
    private ILocationService iLocationService;
    @Autowired
    private ShipmentCache shipmentCache;

    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public boolean save(Initialization entity) {
        if(StrUtil.isBlank(entity.getCode())) {
            entity.setCode(OrderIdGeneratorUtil.generatorOrderId(OrderIdGeneratorUtil.OrderTypeEnum.QC, "",UserUtil.getBranchCode()));
            entity.setWarehouseName(warehouseCache.translate(entity.getWarehouseCode()));
        }
        if(StrUtil.isBlank(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
        }

        // 保存明细
        this.saveItem(entity);
        BigDecimal totalQuantity = entity.getInitializationItemList().stream().map(InitializationItem::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalUnitQuantity = entity.getInitializationItemList().stream().map(InitializationItem::getUnitQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        entity.setTotalQuantity(totalQuantity);
        entity.setTotalUnitQuantity(totalUnitQuantity);

        return super.save(entity);
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor={Exception.class})
    public int updateByCode(Initialization entity) {
        entity.setWarehouseName(warehouseCache.translate(entity.getWarehouseCode()));
        if(StrUtil.isBlank(entity.getModifiedBy())){
            entity.setModifiedBy(UserUtil.getCode());
            entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        }

        List<String> deleteCodes = entity.getDeleteCodes();
        if (IterUtil.isNotEmpty(deleteCodes)) {
            initializationItemService.remove(new QueryWrapper<InitializationItem>().lambda().eq(InitializationItem::getGroupCode,UserUtil.getBranchCode()).in(InitializationItem::getCode, deleteCodes));
        }
        // 保存明细
        this.saveItem(entity);
       /* BigDecimal totalQuantity = entity.getInitializationItemList().stream().map(InitializationItem::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal totalUnitQuantity = entity.getInitializationItemList().stream().map(InitializationItem::getUnitQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
        entity.setTotalQuantity(totalQuantity);
        entity.setTotalUnitQuantity(totalUnitQuantity);*/

        return baseMapper.updateInitializationByCode(entity.getCode(),entity.getStatus());
    }

    /**
     * 查询列表
     * @param initializationDTO
     * @return
     */
    @Override
    public List<InitializationVO> queryList(InitializationDTO initializationDTO){
        // 排序字段名需要驼峰转数据库下划线类型字段名
        if(StrUtil.isNotEmpty(initializationDTO.getSortField())){
            initializationDTO.setSortField(CommonUtil.camel2Underline(initializationDTO.getSortField()));
        }
        return baseMapper.queryList(initializationDTO);
    }

    @Override
    public List<String> queryByGoodsCode(List<String> list) {
        return baseMapper.queryByGoodsCode(list);
    }

    /**
     * 查询合计,包含总数
     * @param initializationDTO
     * @return
     */
    @Override
    public InitializationVO queryListSum(InitializationDTO initializationDTO){
        return baseMapper.queryListSum(initializationDTO);
    }

    /**
     * 根据编码获取VO
     * @param initializationDTO
     * @return
     */
    @Override
    public InitializationVO getOneByCode(InitializationDTO initializationDTO) {
        String code = initializationDTO.getCode();
        Initialization initialization = getOne(new QueryWrapper<Initialization>().lambda().eq(Initialization::getCode, code).eq(Initialization::getGroupCode,UserUtil.getBranchCode()));
        if (ObjectUtil.isNull(initialization)) {
            log.error("期初单【{}】不存在", code);
            throw new ServiceException("期初单号【 " + code + "】不存在！");
        }

        InitializationVO initializationVO = new InitializationVO();
        BeanUtils.copyProperties(initialization, initializationVO);
        initializationVO.setWarehouseName(warehouseCache.translate(initializationVO.getWarehouseCode()));


        InitializationItemDTO initializationItemDTO = new InitializationItemDTO();
        initializationItemDTO.setInitializationCode(code);
        initializationItemDTO.setPageSize(initializationDTO.getPageSize());
        initializationItemDTO.setPageNum(initializationDTO.getPageNum());
        // 获取期初单明细信息
        List<InitializationItemVO> initializationItemList = initializationItemService.queryList(initializationItemDTO);
        initializationItemList.forEach(item -> {
            item.setShipmentName(shipmentCache.translate(item.getShipmentCode()));
           /* List<GoodsUnitConversion> goodsUnitConversionList = goodsUnitConversionCache.get(item.getGoodsCode());
            item.setGoodsUnitConversionList(goodsUnitConversionList);*/
        });
        InitializationItemVO initializationItemVO = initializationItemService.queryListSum(initializationItemDTO);
        initializationVO.setTotal(initializationItemVO.getTotal());
        initializationVO.setWarehouseName(warehouseCache.translate(initialization.getWarehouseCode()));
        initializationVO.setInitializationItemList(initializationItemList);
        return initializationVO;
    }

    /**
     * 删除
     * @param codes
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(List<String> codes) {
        // 遍历删除期初单明细
        codes.forEach(code -> initializationItemService.remove(new QueryWrapper<InitializationItem>().lambda().eq(InitializationItem::getInitializationCode, code)));
        // 删除期初单
        return super.remove(new QueryWrapper<Initialization>().lambda().in(Initialization::getCode, codes).eq(Initialization::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 更新状态
     * @param code
     * @param status
     * @return
     */
    @Override
    public int updateStatusByCode(String code, String status) {
        Initialization initialization = new Initialization();
        initialization.setCode(code);
        initialization.setStatus(status);
        initialization.setModifiedBy(UserUtil.getCode());
        initialization.setModifiedName(partyCache.translate(UserUtil.getCode()));

        return baseMapper.update(initialization, new QueryWrapper<Initialization>().lambda().eq(Initialization::getCode, initialization.getCode()).eq(Initialization::getGroupCode,UserUtil.getBranchCode()));
    }

    /**
     * 审核
     * @param initialization
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int audit(Initialization initialization) {
        String groupCode = UserUtil.getBranchCode();
        Initialization newInitialization = this.getOne(new QueryWrapper<Initialization>().lambda().eq(Initialization::getCode, initialization.getCode()).eq(Initialization::getGroupCode,groupCode));
        if (ObjectUtil.isNull(newInitialization)) {
            throw new ServiceException(INITIALIZATION_NUMBER + initialization.getCode() + NOT_EXIST);
        }
        String receiveLot = OrderIdGeneratorUtil.generatorReceiveLot(newInitialization.getWarehouseCode());

        // 库存日志记录
        List<InventoryRecord> inventoryRecords = new ArrayList<>();

        // 新增库存信息
        List<Inventory> newInv = new ArrayList<>();
        // 旧库存新增信息
        List<Map<String, String>> oldInv = new ArrayList<>();

        // 批次规则map
        Map<String, BatchRule> batchRuleMap = new HashMap<>();
        LocalDateTime now = LocalDateTime.now();
        // 期初审核通过，则生成库存、入库单
        if(InitializationStatusEnum.PASS.getValue().equals(initialization.getStatus())) {
            List<InitializationItem> initializationItemList = initializationItemService.list(new QueryWrapper<InitializationItem>().lambda().eq(InitializationItem::getInitializationCode, initialization.getCode()));
            initializationItemList.parallelStream().forEach(item -> {
                long start = System.currentTimeMillis();
               log.info("---begin");

                Inventory inventory = new Inventory();
                BeanUtils.copyProperties(item, inventory);
                inventory.setGmtStock(now);
                inventory.setUnitName(item.getGoodsUnitName());
                inventory.setGroupCode(groupCode);


                long end = System.currentTimeMillis();
                log.info("1: " + (end-start));
                start = end;

                BatchRule batchRule = null;
                if (batchRuleMap.containsKey(item.getLotNumber())) {
                    batchRule = batchRuleMap.get(item.getLotNumber());
                } else {
                    Map<String, BatchRule> batchRules = batchRuleCache.getAllObjMapByShipmentCode(item.getShipmentCode());
                    if (MapUtil.isNotEmpty(batchRuleMap)) {
                        batchRuleMap.putAll(batchRules);
                        batchRule = batchRules.get(item.getLotNumber());
                    }
                }

                if (batchRule != null && NUM_ONE.equals(batchRule.getLot())) {
                    inventory.setReceiveLot(receiveLot);
                }

                end = System.currentTimeMillis();
                log.info("2: " + (end-start));
                start = end;

                inventory.setLot(OrderIdGeneratorUtil.generatorLot(inventory));
                inventory.setIsLock(NUM_ZERO);
                inventory.setFullLot(OrderIdGeneratorUtil.generatorFullLot(inventory));

                //2021年5月21日  去除存货日期和容器
                Inventory oldInventory = inventoryService.hasSameInventoryQc(inventory.getLot(), item.getGoodsCode(), item.getLocation(),
                        item.getShipmentCode(), item.getGoodsStatus(), inventory.getIsLock());

                end = System.currentTimeMillis();
                log.info("3: " + (end-start));
                start = end;

                // 库存日志记录
                InventoryRecord inventoryRecord;

                if (oldInventory != null) {
                    // 存在相同库存则只需调整库存
//                    inventoryService.adjustQuantity(oldInventory.getCode(), item.getQuantity());
                    Map<String, String> adjustMap = new HashMap<>();
                    adjustMap.put("code", oldInventory.getCode());
                    adjustMap.put("quantity", item.getQuantity().toString());
                    oldInv.add(adjustMap);

                    // 创建库存变动日志
                    inventoryRecord = inventoryRecordService.makeRecord(oldInventory, initialization.getCode(), item.getQuantity(), InventoryRecordTypeEnum.INITIALIZATION.getValue());
                } else {
                    // 不存在相同库存则需要插入一条新库存信息
                    newInv.add(inventory);
                    // 创建库存变动日志
                    inventoryRecord = inventoryRecordService.makeRecord(inventory, initialization.getCode(), item.getQuantity(), InventoryRecordTypeEnum.INITIALIZATION.getValue());
                }

                inventoryRecords.add(inventoryRecord);

                end = System.currentTimeMillis();
                log.info("5: " + (end-start));
            });

            long start2 = System.currentTimeMillis();

            // 批量插入新库存
            if (IterUtil.isNotEmpty(newInv)) {
                //将相同库存的数据进行合并
                List<Inventory> combineSameInv = combineSameInv(newInv);
                batchSaveNewInv(combineSameInv);
            }

            // 批量更新旧库存
            if (IterUtil.isNotEmpty(oldInv)) {
                batchAdjustInv(oldInv);
            }

            // XYTODO  TODO 批量生成库存日志信息
            if (IterUtil.isNotEmpty(inventoryRecords)) {
                saveInventoryRecords(inventoryRecords);
            }


            long end2 = System.currentTimeMillis();
            log.info("6: " + (end2-start2));
            start2 = end2;

            String userCode = UserUtil.getCode();
            String userName = partyCache.translate(userCode);
            LocalDateTime nowTime = LocalDateTime.now();
            String finishStatus = InboundStatusEnum.FINISH_IN.getValue();
            String warehouseCode = newInitialization.getWarehouseCode();

            List<Inbound> inbounds = new ArrayList<>();
            List<InboundItem> inboundItems = new ArrayList<>();
            // 生成期初类型的入库单 根据入驻商分组，不同的入驻商生成不同的入库单
            Map<String, List<InitializationItem>> initializationItemMap = initializationItemList.stream().collect(Collectors.groupingBy(x -> Optional.ofNullable(x.getShipmentCode()).orElse("")));
            initializationItemMap.forEach((key, initializationItems) -> {
                // 生成入库单
                Inbound inbound = new Inbound();
                // 入库单号  RK+入驻商编码+yyyyMMdd+四位流水号
                inbound.setCode(OrderIdGeneratorUtil.generatorOrderId(OrderIdGeneratorUtil.OrderTypeEnum.RK, key,groupCode));
                inbound.setSourceCode(initialization.getCode());
                inbound.setStatus(InboundStatusEnum.FINISH_IN.getValue());
                inbound.setType(ReceiveTypeEnum.INITIALIZATION.getValue());
                inbound.setShipmentCode(key);
                inbound.setWarehouseCode(warehouseCode);
                inbound.setShipmentName(partyCache.translate(key));
                inbound.setGroupCode(newInitialization.getGroupCode());
                inbound.setCreatedBy(userCode);
                inbound.setCreatedName(userName);
                inbound.setGmtCreated(nowTime);

                List<InboundItem> inboundItemList = initializationItems.stream().map(s -> {
                    InboundItem inboundItem = new InboundItem();
                    BeanUtils.copyProperties(s, inboundItem);
                    inboundItem.setCode(IdUtil.simpleUUID());
                    inboundItem.setInboundCode(inbound.getCode());
                    inboundItem.setInboundQuantity(s.getQuantity());
                    inboundItem.setStatus(finishStatus);
                    inboundItem.setCreatedBy(userCode);
                    inboundItem.setCreatedName(userName);
                    inboundItem.setGmtCreated(nowTime);

                    return inboundItem;
                }).collect(Collectors.toList());

                //  计划数量， 取上架单总数量
                BigDecimal totalQuantity = inboundItemList.stream().map(InboundItem::getInboundQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
                inbound.setPlanQuantity(totalQuantity);
                //  入库数量，取上架单数量
                inbound.setInboundQuantity(totalQuantity);

                inbounds.add(inbound);
                inboundItems.addAll(inboundItemList);

            });

            end2 = System.currentTimeMillis();
            log.info("7: " + (end2-start2));
            start2 = end2;

            // XYTODO TODO 批量插入入库单
            inboundService.batchInsert(inbounds);
            inboundItemService.batchInsert(inboundItems);

            end2 = System.currentTimeMillis();
            log.info("8: " + (end2-start2));
        }

        initialization.setGmtApproved(LocalDateTime.now());
        initialization.setApprovedBy(UserUtil.getCode());
        initialization.setApprovedName(partyCache.translate(UserUtil.getCode()));
        initialization.setModifiedBy(UserUtil.getCode());
        initialization.setModifiedName(partyCache.translate(UserUtil.getCode()));
        return baseMapper.update(initialization, new QueryWrapper<Initialization>().lambda().eq(Initialization::getCode, initialization.getCode()).eq(Initialization::getGroupCode,groupCode));
    }

    /**
     * 相同的库存进行合并  背景：如果期初导入的数据完全一样，那么会导致出现多条按下列条件查询的库存，导致getOne方法调用失败
     * @param newInv
     */
    private List<Inventory> combineSameInv(List<Inventory> newInv){
        List<Inventory> inventories = Lists.newArrayList();
        Map<String,List<Inventory>> mapList = newInv.stream().collect(Collectors.groupingBy(info -> info.getLot() + info.getLocation() + info.getGoodsCode() + info.getShipmentCode() + info.getGoodsStatus() + info.getIsLock() + info.getTempInventory() + info.getTempInventory() + info.getJobStatus()));
        mapList.values().stream().forEach(e -> {
            if (e.size() > 1) {
                BigDecimal quantity = e.stream().map(Inventory::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
                Inventory firstInv = e.get(NUM_ZERO);
                firstInv.setQuantity(quantity);
                inventories.add(firstInv);
            }
            inventories.addAll(e);
        });
        return inventories;
    }
    /**
     * 期初导入回显
     * @param initializationExcelDTOList
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<InitializationExcelDTO> initializationView(List<InitializationExcelDTO> initializationExcelDTOList) {
        //校验授权仓库code和入驻商code不能为空
        ShipmentWarehouseValidate.validateShipmentCodesAndWarehouseCodes();

        long start1 = System.currentTimeMillis();

        String branchCode = UserUtil.getBranchCode();
        // 校验Excel里必填项是否有空值
        validateNotBlank(initializationExcelDTOList);

        long end1 = System.currentTimeMillis();
        log.info("a0:" + (end1-start1));
        start1 = end1;

        // 校验仓库是否相同  允许单仓多入驻商导入
        validateSameWarehouse(initializationExcelDTOList);

        end1 = System.currentTimeMillis();
        log.info("a1:" + (end1-start1));
        start1 = end1;

        List<String> authorizeShipmentCodes = UserUtil.getAuthorizeShipmentCodes();
        List<Shipment> shipments = UserUtil.getAuthorizeShipmentList().stream().map(r->BeanUtil.toBean(r,Shipment.class)).collect(Collectors.toList());
        Map<String, Shipment> shipmentMap = shipments.stream().collect(Collectors.toMap(Shipment::getPartyCode, e->e));
        // 校验 当前用户授权的仓库、入驻商
        validateAuthorizationWarehouseShipment(initializationExcelDTOList, authorizeShipmentCodes, branchCode);

        end1 = System.currentTimeMillis();
        log.info("a2:" + (end1-start1));
        start1 = end1;

        // 校验仓库是否启用并且开启库位管理
        validateWarehouseLocationManagement(initializationExcelDTOList, branchCode);

        end1 = System.currentTimeMillis();
        log.info("a3:" + (end1-start1));
        start1 = end1;

        InitializationExcelDTO firstRow = initializationExcelDTOList.get(NUM_ZERO);
        Warehouse warehouse = iWarehouseService.getOne(new QueryWrapper<Warehouse>().lambda().eq(Warehouse::getSerialNumber, firstRow.getWarehouseSerialNumber()).eq(Warehouse::getGroupCode,UserUtil.getBranchCode()));
        String warehouseCode = warehouse.getCode();
        String warehouseName = warehouse.getName();
        // 库区集合
        List<WarehouseSpace> spaceList = iWarehouseSpaceService.list(new QueryWrapper<WarehouseSpace>().lambda().eq(WarehouseSpace::getWarehouseCode, warehouse.getCode()).eq(WarehouseSpace::getGroupCode,UserUtil.getBranchCode()));
        Map<String, WarehouseSpace> spaceMap = spaceList.stream().collect(Collectors.toMap(WarehouseSpace::getSerialNumber, e->e));
        // 库位Map， key为“库区code-库位号”
        List<Location> locationList = iLocationService.list(new QueryWrapper<Location>().lambda().select(Location::getCode,Location::getStatus,Location::getSpaceCode,Location::getSerialNumber).eq(Location::getWarehouseCode, warehouse.getCode()).eq(Location::getGroupCode,UserUtil.getBranchCode())) ;
        Map<String, Location> locationMap = locationList.stream().collect(Collectors.toMap(e->e.getSpaceCode() + "-" + e.getSerialNumber(), e->e));

        end1 = System.currentTimeMillis();
        log.info("a4:" + (end1-start1));
        start1 = end1;
//saas改造入驻商和承运商解除绑定
        // 当前仓库绑定的入驻商信息
//        List<WarehouseShipment> warehouseShipmentList = warehouseShipmentService.list((new LambdaQueryWrapper<WarehouseShipment>().eq(WarehouseShipment::getGroupCode,UserUtil.getBranchCode())));
//        Map<String, Boolean> warehouseShipmentMap = warehouseShipmentList.stream().collect(Collectors.toMap(WarehouseShipment::getShipmentCode, e->true, (key1, key2)->key1));

        // 获取入驻商下的库存状态信息
        List<InventoryStatus> inventoryStatusList = inventoryStatusService.list((new LambdaQueryWrapper<InventoryStatus>().eq(InventoryStatus::getGroupCode,UserUtil.getBranchCode())));
        Map<String, List<InventoryStatus>> inventoryStatusMap = inventoryStatusList.stream().collect(Collectors.groupingBy(InventoryStatus::getShipmentCode));

        end1 = System.currentTimeMillis();
        log.info("a5:" + (end1-start1));
        start1 = end1;

        // 入驻商下的商品信息，第一层key为入驻商code，第二层key为商品编码
        Map<String, Map<String, Goods>> shipmentGoods = new HashMap<>();

        AtomicInteger indexes = new AtomicInteger(0);
        initializationExcelDTOList.parallelStream().forEachOrdered(r-> {
            long start = System.currentTimeMillis();
            long startA = System.currentTimeMillis();

            Integer index = indexes.getAndIncrement();
            // 验证一些字符长度
            String supplier = initializationExcelDTOList.get(index).getSupplier();
            if (StrUtil.isNotBlank(supplier) && StrUtil.length(supplier) > NUM_ONE_HUNDRED.intValue()) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SUPPLIER_NAME + TOO_LONG);
            }
            String serialNumber = initializationExcelDTOList.get(index).getSerialNumber();
            if (StrUtil.isNotBlank(serialNumber) && StrUtil.length(serialNumber) > NUM_ONE_HUNDRED.intValue()) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SERIAL_NUMBER_NAME + TOO_LONG);
            }
            String extendOneStr = initializationExcelDTOList.get(index).getExtendOne();
            if (StrUtil.isNotBlank(extendOneStr) && StrUtil.length(extendOneStr) > NUM_ONE_HUNDRED.intValue()) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_ONE_NAME + TOO_LONG);
            }
            String extendTwoStr = initializationExcelDTOList.get(index).getExtendTwo();
            if (StrUtil.isNotBlank(extendTwoStr) && StrUtil.length(extendTwoStr) > NUM_ONE_HUNDRED.intValue()) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_TWO_NAME + TOO_LONG);
            }
            String remarks = initializationExcelDTOList.get(index).getRemarks();
            if (StrUtil.isNotBlank(remarks) && StrUtil.length(remarks) > TWO_HUNDRED_FIFTY_FIVE.intValue()) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + REMARKS_NAME + TOO_LONG);
            }

            long end = System.currentTimeMillis();
            log.info("1:" + (end-start));
            start = end;


            initializationExcelDTOList.get(index).setWarehouseCode(warehouseCode);
            initializationExcelDTOList.get(index).setWarehouseName(warehouseName);

            Shipment shipment = shipmentMap.get(initializationExcelDTOList.get(index).getShipmentSerialNumber());
            if (shipment == null) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT + NOT_EXIST);
            }
            if (!NUM_THREE.equals(shipment.getAuthStatus())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT + UNAPPROVE_NAME);
            }

//            if (!warehouseShipmentMap.containsKey(shipment.getPartyCode())) {
//                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT_NOT_BELONG_TO_WAREHOUSE);
//            }
            initializationExcelDTOList.get(index).setShipmentCode(shipment.getPartyCode());
            initializationExcelDTOList.get(index).setShipmentName(shipment.getUserName());

            end = System.currentTimeMillis();
            log.info("2:" + (end-start));
            start = end;

            WarehouseSpace space = spaceMap.get(initializationExcelDTOList.get(index).getWarehouseSpaceSerialNumber());
            if (space == null) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_SPACE + NOT_EXIST);
            }
            if (!StatusEnum.ACTIVE.getValue().equals(space.getStatus())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_SPACE + NOT_ENABLED);
            }
            initializationExcelDTOList.get(index).setWarehouseSpaceCode(space.getCode());
            initializationExcelDTOList.get(index).setWarehouseSpaceName(space.getName());

            end = System.currentTimeMillis();
            log.info("3:" + (end-start));
            start = end;

            // 使用“库区code-库位编码”做key获取库位
            String spaceLocationKey = space.getCode() + "-" + initializationExcelDTOList.get(index).getLocationSerialNumber();
            Location location = locationMap.get(spaceLocationKey);
            if (location == null) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + LOCATION + NOT_BELONG_TO + initializationExcelDTOList.get(index).getWarehouseSpaceName());
            }
            if (!StatusEnum.ACTIVE.getValue().equals(location.getStatus())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + LOCATION + NOT_ENABLED);
            }

            end = System.currentTimeMillis();
            log.info("4:" + (end-start));
            start = end;

            initializationExcelDTOList.get(index).setLocation(location.getCode());
            // 优化商品获取操作
            Map<String, Goods> goodsMap = shipmentGoods.get(shipment.getPartyCode());
            if (MapUtil.isEmpty(goodsMap)) {
                List<Goods> goodsList = goodsCache.getAllObjByShipmentCodePure(shipment.getPartyCode());
                if (IterUtil.isEmpty(goodsList)) {
                    throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT + GOODS + NOT_EXIST);
                }
                goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getGoodCode, e->e));
                shipmentGoods.put(shipment.getPartyCode(), goodsMap);
            }

            end = System.currentTimeMillis();
            log.info("5:" + (end-start));
            start = end;
//            System.out.println(goodsMap.toString());
//            Goods goods1 = goodsMap.get("10101105");
//            String goodCode = initializationExcelDTOList.get(index).getGoodCode();
            Goods goods = goodsMap.get(initializationExcelDTOList.get(index).getGoodCode());
            if (goods == null) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS + NOT_EXIST);
            }
            if (!StatusEnum.ACTIVE.getValue().equals(goods.getStatus())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS + NOT_ENABLED);
            }
            initializationExcelDTOList.get(index).setGoodsCode(goods.getCode());
            initializationExcelDTOList.get(index).setGoodsName(goods.getName());
            initializationExcelDTOList.get(index).setGoodsBarCode(goods.getBarCode());
            initializationExcelDTOList.get(index).setLotNumber(goods.getLotNumber());

            end = System.currentTimeMillis();
            log.info("6:" + (end-start));
            start = end;

            List<GoodsUnitConversion> goodsUnitConversions = goodsUnitConversionCache.get(goods.getCode());
            List<GoodsUnitConversion> goodsUnitConversionList = goodsUnitConversions.stream().filter(item -> item.getUnitName().equals(initializationExcelDTOList.get(index).getGoodsUnitName())).collect(Collectors.toList());
            if (CollUtil.isEmpty(goodsUnitConversionList)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS_UNIT + NOT_EXIST);
            }
            Map<String, Object> unitCacheMap = unitCache.get(goodsUnitConversionList.get(NUM_ZERO).getUnitCode());
            if (!StatusEnum.ACTIVE.getValue().equals(unitCacheMap.get(STATUS))) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS_UNIT + NOT_ENABLED);
            }
            initializationExcelDTOList.get(index).setGoodsUnit(goodsUnitConversionList.get(NUM_ZERO).getUnitCode());

            end = System.currentTimeMillis();
            log.info("7:" + (end-start));
            start = end;

            List<GoodsUnitConversion> basicUnitList = goodsUnitConversions.stream().filter(item -> item.getFlag().equals(NUM_ONE)).collect(Collectors.toList());
            initializationExcelDTOList.get(index).setBasicUnit(basicUnitList.get(NUM_ZERO).getUnitCode());
            initializationExcelDTOList.get(index).setBasicUnitName(basicUnitList.get(NUM_ZERO).getUnitName());
            initializationExcelDTOList.get(index).setBasicQuantity(basicUnitList.get(NUM_ZERO).getQuantity());
            initializationExcelDTOList.get(index).setUnitQuantity(new BigDecimal(initializationExcelDTOList.get(index).getInitializationQuantity()));

            end = System.currentTimeMillis();
            log.info("8:" + (end-start));
            start = end;

            List<InventoryStatus> inventoryStatuses = inventoryStatusMap.get(shipment.getPartyCode());
            if (IterUtil.isEmpty(inventoryStatuses)) {
                throw new ServiceException("当前导入入驻商 " + shipment.getPartyCode() + " 没有维护库存状态信息，请确认！");
            }
            if (IterUtil.isEmpty(basicUnitList)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + INVENTORY_STATUS + NOT_EXIST);
            }
            inventoryStatuses = inventoryStatuses.stream().filter(e->initializationExcelDTOList.get(index).getGoodsStatusName().equals(e.getName())).collect(Collectors.toList());
            if (CollUtil.isEmpty(inventoryStatuses)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + INVENTORY_STATUS + NOT_EXIST);
            }
            if (!StatusEnum.ACTIVE.getValue().equals(inventoryStatuses.get(NUM_ZERO).getStatus())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + INVENTORY_STATUS + NOT_ENABLED);
            }
            initializationExcelDTOList.get(index).setGoodsStatus(inventoryStatuses.get(NUM_ZERO).getCode());
            initializationExcelDTOList.get(index).setGoodsStatusName(inventoryStatuses.get(NUM_ZERO).getName());
            initializationExcelDTOList.get(index).setIsConsignment(inventoryStatuses.get(NUM_ZERO).getIsConsignment());

            end = System.currentTimeMillis();
            log.info("9:" + (end-start));
            start = end;

            String gmtManufactureStr = initializationExcelDTOList.get(index).getGmtManufactureStr();
            String gmtExpireStr = initializationExcelDTOList.get(index).getGmtExpireStr();
            String extendThreeStr = initializationExcelDTOList.get(index).getExtendThreeStr();
            String extendFourStr = initializationExcelDTOList.get(index).getExtendFourStr();
            String extendFiveStr = initializationExcelDTOList.get(index).getExtendFiveStr();
            String extendSixStr = initializationExcelDTOList.get(index).getExtendSixStr();

            end = System.currentTimeMillis();
            log.info("10:" + (end-start));
            start = end;

            // 校验商品批次规则
            validateBatchRule(goods.getLotNumber(), gmtManufactureStr, gmtExpireStr, initializationExcelDTOList.get(index).getSupplier(), initializationExcelDTOList.get(index).getSerialNumber(),
                    initializationExcelDTOList.get(index).getExtendOne(), initializationExcelDTOList.get(index).getExtendTwo(), extendThreeStr, extendFourStr, extendFiveStr, extendSixStr, index);

            end = System.currentTimeMillis();
            log.info("11:" + (end-start));
            start = end;


            if (StrUtil.isNotBlank(gmtManufactureStr)) {
                initializationExcelDTOList.get(index).setGmtManufacture(dateFormat(gmtManufactureStr, MANUFACTURE_DATE, index + NUM_THREE));
            }

            if (StrUtil.isNotBlank(gmtExpireStr)) {
                initializationExcelDTOList.get(index).setGmtExpire(dateFormat(gmtExpireStr, EXPIRE_DATE, index + NUM_THREE));
            }

            if (StrUtil.isNotBlank(extendThreeStr)) {
                initializationExcelDTOList.get(index).setExtendThree(numberFormat(extendThreeStr, EXTEND_THREE_NAME, index + NUM_THREE));
            }

            if (StrUtil.isNotBlank(extendFourStr)) {
                initializationExcelDTOList.get(index).setExtendFour(numberFormat(extendFourStr, EXTEND_FOUR_NAME, index + NUM_THREE));
            }

            if (StrUtil.isNotBlank(extendFiveStr)) {
                initializationExcelDTOList.get(index).setExtendFive(dateFormat(extendFiveStr, EXTEND_FIVE_NAME, index + NUM_THREE));
            }

            if (StrUtil.isNotBlank(extendSixStr)) {
                initializationExcelDTOList.get(index).setExtendSix(dateFormat(extendSixStr, EXTEND_SIX_NAME, index + NUM_THREE));
            }

            end = System.currentTimeMillis();
            log.info("12:" + (end-start));

            long endA = System.currentTimeMillis();
            log.info("-------" + (endA-startA));

        });

        initializationCache.removeCache();
        initializationCache.initCache(initializationExcelDTOList);
        return initializationExcelDTOList;
    }

    /**
     * 导入 往数据库插入数据
     */
    @Override
    public void initializationImport() {
        List<InitializationExcelDTO> initializationExcelDTOList = initializationCache.getCache();
        if(CollUtil.isNotEmpty(initializationExcelDTOList)) {
            Initialization initialization = new Initialization();
            initialization.setGroupCode(UserUtil.getBranchCode());
            initialization.setWarehouseCode(initializationExcelDTOList.get(NUM_ZERO).getWarehouseCode());
            initialization.setWarehouseName(initializationExcelDTOList.get(NUM_ZERO).getWarehouseName());
            initialization.setGroupCode(UserUtil.getBranchCode());
            initialization.setStatus(InitializationStatusEnum.NEW.getValue());
            initialization.setCreatedBy(UserUtil.getCode());
            initialization.setCreatedName(partyCache.translate(UserUtil.getCode()));
            initialization.setModifiedBy(UserUtil.getCode());
            initialization.setModifiedName(partyCache.translate(UserUtil.getCode()));

            List<InitializationItem> initializationItemList = initializationExcelDTOList.stream().map(item -> {
                InitializationItem initializationItem = new InitializationItem();
                initializationItem.setInitializationCode(initialization.getCode());
                BeanUtils.copyProperties(item, initializationItem);
                initializationItem.setLocationName(item.getLocationSerialNumber());
                initializationItem.setGmtStock(LocalDateTime.now());

                return initializationItem;
            }).collect(Collectors.toList());

            initialization.setInitializationItemList(initializationItemList);
            save(initialization);
            initializationCache.removeCache();
        }
    }

    /**
     * 保存期初单明细
     * @param entity
     */
    private void saveItem(Initialization entity) {
        entity.getInitializationItemList().forEach(r->{
            if (StrUtil.isNotBlank(r.getCode())) {
                r.setShipmentName(shipmentCache.translate(r.getShipmentCode()));
                r.setLocationName(locationCache.translate(r.getLocation()));
                r.setWarehouseCode(entity.getWarehouseCode());
                r.setWarehouseSpaceName(warehouseSpaceCache.translate(r.getWarehouseSpaceCode()));
                r.setQuantity(r.getUnitQuantity().multiply(r.getBasicQuantity()));
                r.setModifiedBy(UserUtil.getCode());
                r.setModifiedName(partyCache.translate(UserUtil.getCode()));
                r.setGroupCode(UserUtil.getBranchCode());
            } else {
                r.setCode(IdUtil.simpleUUID());
                r.setInitializationCode(entity.getCode());
                r.setWarehouseCode(entity.getWarehouseCode());
                r.setQuantity(r.getUnitQuantity().multiply(r.getBasicQuantity()));
                r.setCreatedBy(UserUtil.getCode());
                r.setGmtCreated(LocalDateTime.now());
                r.setCreatedName(partyCache.translate(UserUtil.getCode()));
                r.setGroupCode(UserUtil.getBranchCode());
            }
        });
        // 批量保存或修改期初单明细
        initializationItemService.saveOrUpdateBatch(entity.getInitializationItemList());
    }

    /**
     * 校验仓库是否相同
     * @param initializationExcelDTOList
     */
    private void validateSameWarehouse(List<InitializationExcelDTO> initializationExcelDTOList) {
        initializationExcelDTOList.forEach(item -> {
            initializationExcelDTOList.forEach(item1 -> {
                if(!item.getWarehouseSerialNumber().equals(item1.getWarehouseSerialNumber())) {
                    throw new ServiceException(EXIST + WAREHOUSE_SERIAL_NUMBER + NOT_SAME + DATA_NAME);
                }
            });
        });
    }

    /**
     * 校验仓库是否启用并且开启库位管理
     * @param initializationExcelDTOList
     */
    private void validateWarehouseLocationManagement(List<InitializationExcelDTO> initializationExcelDTOList, String branchCode) {
        List<Map<String, Object>> warehouseCacheAll = warehouseCache.getAllByGroupCode(branchCode);
        List<Map<String, Object>> warehouseMaps = warehouseCacheAll.stream().filter(item -> item.get(SERIAL_NUMBER).equals(initializationExcelDTOList.get(NUM_ZERO).getWarehouseSerialNumber()) && branchCode.equals(item.get(GROUP_CODE))).collect(Collectors.toList());
        if(CollUtil.isEmpty(warehouseMaps)) {
            throw new ServiceException(WAREHOUSE + NOT_EXIST);
        }
        String status = (String) warehouseMaps.get(NUM_ZERO).get(STATUS);
        if(!StatusEnum.ACTIVE.getValue().equals(status)) {
            throw new ServiceException(WAREHOUSE + NOT_ENABLED);
        }
        Integer locationManagement = (Integer) warehouseMaps.get(NUM_ZERO).get(LOCATION_MANAGEMENT);
        if(!NUM_ONE.equals(locationManagement)) {
            throw new ServiceException(WAREHOUSE + NOT_LOCATION_MANAGEMENT);
        }
    }

    /**
     * 校验Excel里必填项是否有空值
     * @param initializationExcelDTOList
     */
    private void validateNotBlank(List<InitializationExcelDTO> initializationExcelDTOList) {
        for(int index = NUM_ZERO; index < initializationExcelDTOList.size(); index++){
            // 校验Excel里必填项是否有空值
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getWarehouseSerialNumber())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_SERIAL_NUMBER + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getWarehouseName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_NAME + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getShipmentSerialNumber())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT_SERIAL_NUMBER + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getShipmentName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SHIPMENT_NAME + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getWarehouseSpaceSerialNumber())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_SPACE_SERIAL_NUMBER + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getWarehouseSpaceName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + WAREHOUSE_SPACE_NAME + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getLocationSerialNumber())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + LOCATION_SERIAL_NUMBER + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getGoodCode())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOOD_CODE_NAME + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getGoodsName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS_NAME_TEXT + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getGoodsUnitName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GOODS_UNIT + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getInitializationQuantity())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + QUANTITY + NOT_BLANK);
            }
            if (StrUtil.isBlank(initializationExcelDTOList.get(index).getGoodsStatusName())) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + INVENTORY_STATUS + NOT_BLANK);
            }
        }
    }

    /**
     * 校验是否有重复数据
     * @param initializationExcelDTOList
     */
    private void validateRepeatData(List<InitializationExcelDTO> initializationExcelDTOList) {
        List<InitializationExcelDTO> initializationExcelList = initializationExcelDTOList;
        Stream.iterate(NUM_ZERO, index -> index + NUM_ONE).limit(initializationExcelDTOList.size()).forEach(index -> {
            Stream.iterate(NUM_ZERO, indexJ -> indexJ + NUM_ONE).limit(initializationExcelList.size()).forEach(indexJ -> {
                boolean warehouseFlag = initializationExcelDTOList.get(index).getWarehouseSerialNumber().equals(initializationExcelList.get(indexJ).getWarehouseSerialNumber());
                boolean shipmentFlag = initializationExcelDTOList.get(index).getShipmentSerialNumber().equals(initializationExcelList.get(indexJ).getShipmentSerialNumber());
                boolean warehouseSpaceFlag = initializationExcelDTOList.get(index).getWarehouseSpaceSerialNumber().equals(initializationExcelList.get(indexJ).getWarehouseSpaceSerialNumber());
                boolean locationFlag = initializationExcelDTOList.get(index).getLocationSerialNumber().equals(initializationExcelList.get(indexJ).getLocationSerialNumber());
                boolean goodsFlag = initializationExcelDTOList.get(index).getGoodCode().equals(initializationExcelList.get(indexJ).getGoodCode());
                boolean goodsStatusFlag = initializationExcelDTOList.get(index).getGoodsStatusName().equals(initializationExcelList.get(indexJ).getGoodsStatusName());

                if(warehouseFlag && shipmentFlag && warehouseSpaceFlag && locationFlag && goodsFlag && goodsStatusFlag && !index.equals(indexJ)) {
                    throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + AND_NAME + TIP_PREFIX + (indexJ + NUM_THREE) + LINE + REPEAT_DATA);
                }
            });
        });
    }

    /**
     * 校验 商品批次规则
     * @param batchRuleCode
     * @param gmtManufacture
     * @param gmtExpire
     * @param supplierCode
     * @param serialNumber
     * @param extendOne
     * @param extendTwo
     * @param extendThree
     * @param extendFour
     * @param extendFive
     * @param extendSix
     * @param index
     */
    private void validateBatchRule(String batchRuleCode, String gmtManufacture, String gmtExpire, String supplierCode, String serialNumber, String extendOne,
                                   String extendTwo, String extendThree, String extendFour, String extendFive, String extendSix, Integer index) {
        Map<String, Object> batchRule = batchRuleCache.get(batchRuleCode);
        if (MapUtil.isEmpty(batchRule)) {
            return;
        }
        if (StatusEnum.ACTIVE.getValue().equals(batchRule.get(STATE))) {
            Integer gmtManufactureValue = (Integer) batchRule.get(GMT_MANUFACTURE);
            Integer gmtExpireValue = (Integer) batchRule.get(GMT_EXPIRE);
            Integer supplierCodeValue = (Integer) batchRule.get(SUPPLIER_CODE);
            Integer serialNumberValue = (Integer) batchRule.get(SERIAL_NUMBER);
            Integer extendOneValue = (Integer) batchRule.get(EXTEND_ONE);
            Integer extendTwoValue = (Integer) batchRule.get(EXTEND_TWO);
            Integer extendThreeValue = (Integer) batchRule.get(EXTEND_THREE);
            Integer extendFourValue = (Integer) batchRule.get(EXTEND_FOUR);
            Integer extendFiveValue = (Integer) batchRule.get(EXTEND_FIVE);
            Integer extendSixValue = (Integer) batchRule.get(EXTEND_SIX);

            if(NUM_ONE.equals(gmtManufactureValue) && StrUtil.isEmpty(gmtManufacture)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GMT_MANUFACTURE_NAME + NOT_BLANK);
            }

            if(NUM_ONE.equals(gmtExpireValue) && StrUtil.isEmpty(gmtExpire)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + GMT_EXPIRE_NAME + NOT_BLANK);
            }

            if(NUM_ONE.equals(supplierCodeValue) && StrUtil.isEmpty(supplierCode)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SUPPLIER_NAME + NOT_BLANK);
            }

            if(NUM_ONE.equals(serialNumberValue) && StrUtil.isEmpty(serialNumber)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + SERIAL_NUMBER_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendOneValue) && StrUtil.isEmpty(extendOne)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_ONE_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendTwoValue) && StrUtil.isEmpty(extendTwo)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_TWO_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendThreeValue) && StrUtil.isEmpty(extendThree)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_THREE_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendFourValue) && StrUtil.isEmpty(extendFour)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_FOUR_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendFiveValue) && StrUtil.isEmpty(extendFive)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_FIVE_NAME + NOT_BLANK);
            }
            if(NUM_ONE.equals(extendSixValue) && StrUtil.isEmpty(extendSix)) {
                throw new ServiceException(TIP_PREFIX + (index + NUM_THREE) + LINE + EXTEND_SIX_NAME + NOT_BLANK);
            }
        }
    }

    /**
     * 校验 当前用户授权的仓库、入驻商
     * @param initializationExcelDTOList
     * @param branchCode
     */
    private void validateAuthorizationWarehouseShipment(List<InitializationExcelDTO> initializationExcelDTOList, List<String> shipmentsCodes, String branchCode) {

        List<Map<String,Object>> warehouseList = UserUtil.getAuthorizeWarehouseList();
        if(IterUtil.isEmpty(warehouseList)){
            throw new ServiceException(CURRENT_USER_NAME + WITHOUT + WAREHOUSE + PERMISSIONS);
        }

        String warehouseSerialNumber = initializationExcelDTOList.get(NUM_ZERO).getWarehouseSerialNumber();

        boolean bool = warehouseList.stream().map(r->
                BeanUtil.toBean(r,Warehouse.class)
        ).map(Warehouse::getGroupCode).filter(s->StrUtil.equals(branchCode,s)).count()>0;

        boolean bool2 = warehouseList.stream().map(r->
                BeanUtil.toBean(r,Warehouse.class)
        ).map(Warehouse::getSerialNumber).filter(s->StrUtil.equals(warehouseSerialNumber,s)).count()>0;

        if (!bool || !bool2) {
            throw new ServiceException(CURRENT_USER_NAME + WITHOUT + WAREHOUSE + LEFT_BRACKET + warehouseSerialNumber + RIGHT_BRACKET + PERMISSIONS);
        }

        Map<String, List<InitializationExcelDTO>> initializationExcelMap = initializationExcelDTOList.stream().collect(Collectors.groupingBy(x -> Optional.ofNullable(x.getShipmentSerialNumber()).orElse("")));
        initializationExcelMap.entrySet().stream().forEach(e -> {

            if (!shipmentsCodes.contains(e.getKey())) {
                throw new ServiceException(CURRENT_USER_NAME + WITHOUT + SHIPMENT + LEFT_BRACKET + e.getKey() + RIGHT_BRACKET + PERMISSIONS);
            }
        });




    }

    /**
     * 格式化日期
     * @param dateTimeStr
     * @param formatStr
     * @param index
     * @return
     */
    private LocalDateTime dateFormat(String dateTimeStr, String formatStr, Integer index) {
        try {
            return LocalDateTime.parse(dateTimeStr + DATE_SUFFIX, df);
        }catch (Exception e) {
            throw new ServiceException(TIP_PREFIX + index + LINE + formatStr + DATE_FORMAT_EXCEPTION);
        }
    }

    /**
     * 格式化数字
     * @param numberStr
     * @param formatStr
     * @param index
     * @return
     */
    private BigDecimal numberFormat(String numberStr, String formatStr, Integer index) {
        try {
            return new BigDecimal(numberStr);
        }catch (Exception e) {
            throw new ServiceException(TIP_PREFIX + index + LINE + formatStr + NUM_FORMAT_EXCEPTION);
        }
    }


    /**
     * 批量保存库存日志数据
     * @param records
     */
    @Transactional(rollbackFor = {Exception.class})
    public void saveInventoryRecords(List<InventoryRecord> records) {
        String createdBy = UserUtil.getCode();
        String createdName = partyCache.translate(createdBy);
        LocalDateTime nowTime = LocalDateTime.now();
        StringBuilder invRecordSql = new StringBuilder();
        // 商品sql
        invRecordSql.append("insert into `wms_inventory_record` ( `id`, `code`, `shipment_code`, `shipment_name`, " +
                "`warehouse_space_code`, `location`, `inventory_code`, `warehouse_code`, `goods_code`, `goods_name`, " +
                "`expiration_quantity`, `goods_unit`, `unit_name`, `goods_bar_code`, `good_code`, `gmt_manufacture`," +
                " `gmt_expire`, `gmt_stock`, `supplier`, `serial_number`, `extend_one`, `extend_two`, `extend_three`," +
                " `extend_four`, `extend_five`, `extend_six`, `spec`, `source_code`, `lot`, `receive_lot`, `is_lock`," +
                " `goods_status`, `goods_status_name`, `type`, `num`, `remarks`, `is_deleted`, `created_by`," +
                " `created_name`, `gmt_created`, `modified_by`, `gmt_modified`, `modified_name`," +
                " `container_bar_code`, `group_code`) values ");

        String data = records.stream().map(r -> {
            r.setDeleted(NUM_ZERO);
            return makeInvRecordInsertValueStr(r, createdBy, createdName, nowTime);
        }).collect(Collectors.joining(","));
        invRecordSql.append(data);

        inventoryRecordService.execSql(invRecordSql.toString());

    }

    /**
     * 创建库存日志sql的插入语句数据
     * @param record
     * @param createdBy
     * @param createdName
     * @param nowTime
     * @return
     */
    public String makeInvRecordInsertValueStr(InventoryRecord record, String createdBy, String createdName, LocalDateTime nowTime) {
        StringBuilder data = new StringBuilder();
        data.append("(");
        // id
        data.append("default, ");
        // code
        data.append("'").append(record.getCode()).append("',");
        // shipment_code
        data.append("'").append(record.getShipmentCode()).append("',");
        // shipment_name
        data.append("'").append(record.getShipmentName()).append("',");
        // warehouse_space_code
        data.append("'").append(record.getWarehouseSpaceCode()).append("',");
        // location
        data.append("'").append(record.getLocation()).append("',");
        // inventory_code
        data.append("'").append(record.getInventoryCode()).append("',");
        // warehouse_code
        data.append("'").append(record.getWarehouseCode()).append("',");
        // goods_code
        data.append("'").append(record.getGoodsCode()).append("',");
        // goods_name
        data.append("'").append(record.getGoodsName()).append("',");
        // expiration_quantity
        if (ObjectUtil.isNull(record.getExpirationQuantity())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExpirationQuantity()).append("',");
        }
        // goods_unit
        data.append("'").append(record.getGoodsUnit()).append("',");
        // unit_name
        data.append("'").append(record.getUnitName()).append("',");
        // goods_bar_code
        data.append("'").append(record.getGoodsBarCode()).append("',");
        // good_code
        data.append("'").append(record.getGoodCode()).append("',");
        // gmt_manufacture
        if (ObjectUtil.isNull(record.getGmtManufacture())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtManufacture()).append("',");
        }
        // gmt_expire
        if (ObjectUtil.isNull(record.getGmtExpire())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtExpire()).append("',");
        }
        // gmt_stock
        if (ObjectUtil.isNull(record.getGmtStock())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtStock()).append("',");
        }
        // supplier
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSupplier(), StrUtil.EMPTY)).append("',");
        // serial_number
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSerialNumber(), StrUtil.EMPTY)).append("',");
        // extend_one
        data.append("'").append(ObjectUtil.defaultIfNull(record.getExtendOne(), StrUtil.EMPTY)).append("',");
        // extend_two
        data.append("'").append(ObjectUtil.defaultIfNull(record.getExtendTwo(), StrUtil.EMPTY)).append("',");
        // extend_three
        if (ObjectUtil.isNull(record.getExtendThree())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendThree()).append("',");
        }
        // extend_four
        if (ObjectUtil.isNull(record.getExtendFour())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendFour()).append("',");
        }
        // extend_five
        if (ObjectUtil.isNull(record.getExtendFive())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendFive()).append("',");
        }
        // extend_six
        if (ObjectUtil.isNull(record.getExtendSix())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendSix()).append("',");
        }
        // spec
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSpec(), StrUtil.EMPTY)).append("',");
        // source_code
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSourceCode(), StrUtil.EMPTY)).append("',");
        // lot
        data.append("'").append(ObjectUtil.defaultIfNull(record.getLot(), StrUtil.EMPTY)).append("',");
        // receive_lot
        data.append("'").append(ObjectUtil.defaultIfNull(record.getReceiveLot(), StrUtil.EMPTY)).append("',");
        // is_lock
        data.append(record.getIsLock()).append(",");
        // goods_status
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGoodsStatus(), StrUtil.EMPTY)).append("',");
        // goods_status_name
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGoodsStatusName(), StrUtil.EMPTY)).append("',");
        // type
        data.append("'").append(ObjectUtil.defaultIfNull(record.getType(), StrUtil.EMPTY)).append("',");
        // num
        data.append(ObjectUtil.defaultIfNull(record.getNum(), StrUtil.NULL)).append(",");
        // remarks
        data.append("'").append(ObjectUtil.defaultIfNull(record.getRemarks(), StrUtil.EMPTY)).append("',");
        // is_deleted
        data.append("'").append(record.getDeleted()).append("',");
        // created_by
        data.append("'").append(createdBy).append("',");
        // created_name
        data.append("'").append(createdName).append("',");
        // gmt_created
        data.append("'").append(nowTime).append("',");
        // modified_by
        data.append("'").append(createdBy).append("',");
        // gmt_modified
        data.append("'").append(nowTime).append("',");
        // modified_name
        data.append("'").append(createdName).append("',");
        // container_bar_code
        data.append("'").append(ObjectUtil.defaultIfNull(record.getContainerBarCode(), StrUtil.EMPTY)).append("',");
        // group_code
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGroupCode(), StrUtil.EMPTY)).append("'");


        data.append(")");

        return  data.toString();
    }

    /**
     * 批量新增库存信息
     * @param inventories
     */
    public void batchSaveNewInv(List<Inventory> inventories) {
        String createdBy = UserUtil.getCode();
        String createdName = partyCache.translate(createdBy);
        LocalDateTime nowTime = LocalDateTime.now();
        StringBuilder sql = new StringBuilder();
        // 商品sql
        sql.append("insert into `wms_inventory` ( `id`, `code`, `warehouse_code`, `warehouse_space_code`, " +
                " `shipment_code`, `shipment_name`, `goods_code`, `good_code`, `goods_bar_code`, `spec`, " +
                " `expiration_quantity`, `goods_name`, `unit_name`, `goods_unit`, `use_quantity`, `quantity`, `location`," +
                " `gmt_manufacture`, `gmt_expire`, `gmt_stock`, `lot`, `receive_lot`, `is_lock`, `status`, `goods_status`," +
                " `goods_status_name`, `is_deleted`, `created_by`, `gmt_created`, `modified_by`, `gmt_modified`, " +
                " `supplier`, `serial_number`, `extend_one`, `extend_two`, `extend_three`, `extend_four`,`extend_five`, " +
                " `extend_six`, `created_name`, `modified_name`, `is_temp_inventory`, `old_inventory_code`," +
                " `group_code`,`full_lot`) values ");

        String data = inventories.stream().map(r -> {
            r.setDeleted(NUM_ZERO);
            return makeInventoryInsertValueStr(r, createdBy, createdName, nowTime);
        }).collect(Collectors.joining(","));
        sql.append(data);

        inventoryService.execSql(sql.toString());
    }


    /**
     * 创建库存日志sql的插入语句数据
     * @param record
     * @param createdBy
     * @param createdName
     * @param nowTime
     * @return
     */
    public String makeInventoryInsertValueStr(Inventory record, String createdBy, String createdName, LocalDateTime nowTime) {
        StringBuilder data = new StringBuilder();
        data.append("(");
        // id
        data.append("default, ");
        // code
        data.append("'").append(IdUtil.simpleUUID()).append("',");
        // warehouse_code
        data.append("'").append(record.getWarehouseCode()).append("',");
        // warehouse_space_code
        data.append("'").append(record.getWarehouseSpaceCode()).append("',");
        // shipment_code
        data.append("'").append(record.getShipmentCode()).append("',");
        // shipment_name
        data.append("'").append(record.getShipmentName()).append("',");
        // goods_code
        data.append("'").append(record.getGoodsCode()).append("',");
        // good_code
        data.append("'").append(record.getGoodCode()).append("',");
        // goods_bar_code
        data.append("'").append(record.getGoodsBarCode()).append("',");
        // spec
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSpec(), StrUtil.EMPTY)).append("',");
        // expiration_quantity
        if (ObjectUtil.isNull(record.getExpirationQuantity())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExpirationQuantity()).append("',");
        }
        // goods_name
        data.append("'").append(record.getGoodsName()).append("',");
        // unit_name
        data.append("'").append(record.getUnitName()).append("',");
        // goods_unit
        data.append("'").append(record.getGoodsUnit()).append("',");
        // use_quantity
        data.append(BigDecimal.ZERO).append(",");
        // quantity
        data.append(record.getQuantity()).append(",");
        // location
        data.append("'").append(record.getLocation()).append("',");
        // gmt_manufacture
        if (ObjectUtil.isNull(record.getGmtManufacture())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtManufacture()).append("',");
        }
        // gmt_expire
        if (ObjectUtil.isNull(record.getGmtExpire())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtExpire()).append("',");
        }
        // gmt_stock
        if (ObjectUtil.isNull(record.getGmtStock())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getGmtStock()).append("',");
        }
        // lot
        data.append("'").append(ObjectUtil.defaultIfNull(record.getLot(), StrUtil.EMPTY)).append("',");
        // receive_lot
        data.append("'").append(ObjectUtil.defaultIfNull(record.getReceiveLot(), StrUtil.EMPTY)).append("',");
        // is_lock
        data.append(record.getIsLock()).append(",");
        // status
        data.append(StrUtil.NULL).append(",");
        // goods_status
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGoodsStatus(), StrUtil.EMPTY)).append("',");
        // goods_status_name
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGoodsStatusName(), StrUtil.EMPTY)).append("',");
        // is_deleted
        data.append(NUM_ZERO).append(",");
        // created_by
        data.append("'").append(createdBy).append("',");
        // gmt_created
        data.append("'").append(nowTime).append("',");
        // modified_by
        data.append("'").append(createdBy).append("',");
        // gmt_modified
        data.append("'").append(nowTime).append("',");
        // supplier
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSupplier(), StrUtil.EMPTY)).append("',");// serial_number
        data.append("'").append(ObjectUtil.defaultIfNull(record.getSerialNumber(), StrUtil.EMPTY)).append("',");
        // extend_one
        data.append("'").append(ObjectUtil.defaultIfNull(record.getExtendOne(), StrUtil.EMPTY)).append("',");
        // extend_two
        data.append("'").append(ObjectUtil.defaultIfNull(record.getExtendTwo(), StrUtil.EMPTY)).append("',");
        // extend_three
        if (ObjectUtil.isNull(record.getExtendThree())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendThree()).append("',");
        }
        // extend_four
        if (ObjectUtil.isNull(record.getExtendFour())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendFour()).append("',");
        }
        // extend_five
        if (ObjectUtil.isNull(record.getExtendFive())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendFive()).append("',");
        }
        // extend_six
        if (ObjectUtil.isNull(record.getExtendSix())) {
            data.append(StrUtil.NULL).append(",");
        } else {
            data.append("'").append(record.getExtendSix()).append("',");
        }
        // created_name
        data.append("'").append(createdName).append("',");
        // modified_name
        data.append("'").append(createdName).append("',");
        // is_temp_inventory
        data.append("'").append(NUM_ZERO).append("',");
        // old_inventory_code
        data.append("'").append(StrUtil.EMPTY).append("',");
        // group_code
        data.append("'").append(ObjectUtil.defaultIfNull(record.getGroupCode(), StrUtil.EMPTY)).append("',");
        data.append("'").append(record.getFullLot()).append("'");

        data.append(")");

        return  data.toString();
    }

    /**
     * 批量处理调整库存sql
     */
    @Transactional(rollbackFor = {Exception.class})
    public void batchAdjustInv(List<Map<String, String>> maps) {
        String sql = maps.stream().map(r -> makeAdjustInvSqlStr(r)).collect(Collectors.joining(";"));
        inventoryService.execSql(sql);
    }

    /**
     * 生成更新库存sql
     * @param map
     * @return
     */
    public String makeAdjustInvSqlStr(Map<String, String> map) {
        return "update wms_inventory set quantity = quantity + " + map.get("quantity") + " where code = '" + map.get("code") +"'";
    }

}
